package com.suncky.frame.http.coroutines

import com.google.gson.JsonParseException
import com.suncky.frame.http.bean.ErrorResult
import com.suncky.frame.http.bean.Page
import com.suncky.frame.utils.LogUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import org.json.JSONException
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.text.ParseException
import javax.net.ssl.SSLHandshakeException

abstract class KRequest<E, P : Page, R : KResult<E, P>,ER:ErrorResult> : CoroutineScope by MainScope() {

    /**
     * 挂起方式执行数据请求,返回数据结果实例
     */
    suspend fun execute(block: suspend () -> R): R? {
        return try {
            val response = block()
            if (response.isSuccess || !onHandleError(response.code, response.message)) {
                response
            } else {
                null
            }
        } catch (e: Exception) {
            e.printStackTrace()
            val errorResult=onGetErrorResult(e)
            if (!onHandleException(e,errorResult)) {
                onCreateExceptionResult(e,errorResult)
            } else {
                null
            }

        }
    }

    /**
     * 非挂起方式执行数据请求,处理数据请求结果
     */
    fun execute(onResult: (result: R?) -> Unit, block: suspend () -> R) {
        launch {
            onResult(execute(block))
        }
    }

    /**
     * 生成异常情况下的KResult实例
     */
    abstract fun onCreateExceptionResult(e: Exception,errorResult: ER?): R

    /**
     * 非挂起方式执行数据请求,分开处理数据请求结果
     */
    fun execute(
        successAction: ((data: E?, dataPage: P?) -> Unit)?,
        errorAction: ((code: Int?, message: String?) -> Unit)?, block: suspend () -> R
    ) {
        launch {
            try {
                val result = block()
                if (result.isSuccess) {
                    successAction?.invoke(result.data, result.page)
                } else {
                    if (!onHandleError(result.code, result.message)) {
                        errorAction?.invoke(result.code, result.message)
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
                val errorResult=onGetErrorResult(e)
                if (!onHandleException(e,errorResult)) {
                    processException(e,errorResult, errorAction)
                }
            }

        }
    }

    private fun processException(
        e: Exception,errorResult: ER?,
        errorAction: ((code: Int?, message: String?) -> Unit)?
    ) {
        when (e) {
            is HttpException -> {
                if (errorResult != null) {
                    errorAction?.invoke(errorResult.getStatusCode(), errorResult.getMessage())
                }else{
                    errorAction?.invoke(e.code(), e.message)
                }
            }
            is ConnectException -> errorAction?.invoke(
                KError.CONNECT_FAIL.code,
                KError.CONNECT_FAIL.message
            )
            is SocketTimeoutException -> errorAction?.invoke(
                KError.SOCKET_TIMEOUT.code,
                KError.SOCKET_TIMEOUT.message
            )
            is UnknownHostException -> errorAction?.invoke(
                KError.UNKNOWN_HOST.code,
                KError.UNKNOWN_HOST.message
            )
            is JsonParseException,
            is JSONException,
            is ParseException -> errorAction?.invoke(
                KError.JSON_ERROR.code,
                KError.JSON_ERROR.message
            )
            is SSLHandshakeException -> errorAction?.invoke(
                KError.SSL_HANDSHAKE.code,
                KError.SSL_HANDSHAKE.message
            )
            else -> {
                errorAction?.invoke(
                    KError.UNKNOWN_ERROR.code,
                    e.message
                )
            }
        }
    }


    /**
     * 错误信息预处理
     * @return true-消费错误事件 false-不消费错误事件
     */
    abstract fun onHandleError(code: Int?, message: String?): Boolean

    /**
     * http异常预处理
     * @return true-消费异常事件 false-不消费异常事件
     */
    abstract fun onHandleException(e: Exception,errorResult: ER?):Boolean

    abstract fun onGetErrorResult(e: Exception):ER?
}